package v1

import (
	"fmt"
	"gin-wheel/app/service"
	"gin-wheel/global"
	"gin-wheel/pkg/app"
	"gin-wheel/pkg/errcode"
	"gin-wheel/pkg/util"

	"github.com/dgrijalva/jwt-go"
	"github.com/gin-gonic/gin"
)

type user struct {
}

func NewUser() *user {
	return &user{}
}

func (u *user) Register(c *gin.Context) {
	// 绑定参数并验证参数
	param := service.RegisterRequest{}
	response := app.NewResponse(c)
	valid, errs := app.BindAndValid(c, &param)
	if !valid {
		info := fmt.Sprintf("app.BindAndValid errs: %v", errs)
		global.ZapLog.Error(info)
		response.ToResponse(errcode.InvalidParams, nil)
		return
	}

	// 初始化service
	svc := service.NewService(c.Request.Context(), global.MysqlConnMaps["gw"])

	// 验证用户名或者手机号是否重复注册
	userByName, err := svc.UserInfo(param.UserName, "")
	userByPhone, err := svc.UserInfo("", param.Phone)
	if err != nil {
		info := fmt.Sprintf("get new user errs: %v", err)
		global.ZapLog.Error(info)
		response.ToResponse(errcode.GetUserFailError, nil)
		return
	}
	if userByName.ID > 0 {
		response.ToResponse(errcode.UserNameRegisteredError, nil)
		return
	}
	if userByPhone.ID > 0 {
		response.ToResponse(errcode.PhoneRegisteredError, nil)
		return
	}

	// 执行创建用户的逻辑
	newUser, err := svc.Register(param)
	if err != nil {
		info := fmt.Sprintf("register new user errs: %v", err)
		global.ZapLog.Error(info)
		response.ToResponse(errcode.RegisterFailError, nil)
		return
	}
	response.ToResponse(errcode.Success, gin.H{"userid": util.EnHashids([]int{int(newUser.ID)})})
	return
}

// 根据登录名和密码登录
func (u *user) Login(c *gin.Context) {
	resp := app.NewResponse(c)
	param := service.LoginParam{}

	// 验证参数
	valid, errs := app.BindAndValid(c, &param)
	if !valid {
		info := fmt.Sprintf("login error: %v", errs)
		global.ZapLog.Error(info)
		resp.ToResponse(errcode.InvalidParams, nil)
		return
	}

	// 初始化service
	svc := service.NewService(c.Request.Context(), global.MysqlConnMaps["gw"])
	loginOk, err := svc.Login(param.LoginName, param.Password)
	if err != nil {
		global.ZapLog.Error(fmt.Sprintf("login err: %v", err))
		resp.ToResponse(errcode.LoginFailError, nil)
		return
	}
	if !loginOk {
		resp.ToResponse(errcode.UsernameOrPasswordError, nil)
		return
	}

	// 查询出登录用户的信息
	userid := 0
	username := ""
	phone := ""
	userByName, err := svc.UserInfo(param.LoginName, "")
	userByPhone, err := svc.UserInfo("", param.LoginName)
	if userByName.ID > 0 {
		userid = int(userByName.ID)
		username = userByName.UserName
		phone = userByName.Phone
	} else {
		if userByPhone.ID > 0 {
			userid = int(userByPhone.ID)
			username = userByPhone.UserName
			phone = userByPhone.Phone
		} else {
			global.ZapLog.Error(fmt.Sprintf("login err: %v", "数据库中无此记录"))
			resp.ToResponse(errcode.LoginFailError, nil)
			return
		}

	}
	access_token, err := app.GenerateToken(userid, username, phone, global.JWTSetting.CreatedExpire)
	if err != nil {
		global.ZapLog.Error(fmt.Sprintf("generate access token fail: %v", err))
		resp.ToResponse(errcode.UnauthorizedTokenGenerate, nil)
		return
	}
	refresh_token, err := app.GenerateToken(userid, username, phone, global.JWTSetting.RefreshExpire)
	if err != nil {
		global.ZapLog.Error(fmt.Sprintf("generate refresh token fail: %v", err))
		resp.ToResponse(errcode.UnauthorizedTokenGenerate, nil)
		return
	}
	resp.ToResponse(errcode.Success, gin.H{"access_token": access_token, "refresh_token": refresh_token})
	return
}

// 当access_token时效时候使用refresh_token重新获取token
func (u *user) RefreshToken(c *gin.Context) {
	resp := app.NewResponse(c)
	param := service.RefreshTokenParam{}

	// 验证参数
	valid, errs := app.BindAndValid(c, &param)
	if !valid {
		info := fmt.Sprintf("valid refresh_token param error: %v", errs)
		global.ZapLog.Error(info)
		resp.ToResponse(errcode.InvalidParams, nil)
		return
	}

	// 验证refresh_token是否过期
	_, err := app.ParseToken(param.RefreshToken)
	ecode := errcode.Success
	if err != nil {
		switch err.(*jwt.ValidationError).Errors {
		case jwt.ValidationErrorExpired:
			ecode = errcode.UnauthorizedTokenTimeout
		default:
			ecode = errcode.UnauthorizedTokenError
		}
		global.ZapLog.Error("parse refresh_token fail, resp: " + ecode.Msg)
		resp.ToResponse(ecode, nil)
		return
	} else {
		claims, err := app.ParseToken(param.RefreshToken)
		if err != nil {
			info := fmt.Sprintf("parse refresh token err: %v", err)
			global.ZapLog.Error(info)
			resp.ToResponse(errcode.InvalidParams, nil)
			return
		} else {
			// 解析出原始userid 再次生成token
			oriUserid := util.DeHashids(claims.Userid)[0]
			access_token, err := app.GenerateToken(oriUserid, claims.Username, claims.Phone, global.JWTSetting.CreatedExpire)
			if err != nil {
				global.ZapLog.Error(fmt.Sprintf("generate access token fail: %v", err))
				resp.ToResponse(errcode.UnauthorizedTokenGenerate, nil)
				return
			}
			refresh_token, err := app.GenerateToken(oriUserid, claims.Username, claims.Phone, global.JWTSetting.RefreshExpire)
			if err != nil {
				global.ZapLog.Error(fmt.Sprintf("generate refresh token fail: %v", err))
				resp.ToResponse(errcode.UnauthorizedTokenGenerate, nil)
				return
			}
			resp.ToResponse(errcode.Success, gin.H{"access_token": access_token, "refresh_token": refresh_token})
		}
	}

}

func (u *user) TestRedis(c *gin.Context) {

	// redisClient := pkg.GetOneRedisClient()
	// defer redisClient.ReleaseOneRedisClient()

	// res, err := redisClient.Execute("GET", "FOO")
	// if err != nil {
	// 	panic(err)
	// }
	resp := app.NewResponse(c)
	resp.ToResponse(errcode.Success, nil)
	return
}
